package org.realteam.example.service;

import java.io.Serializable;
import java.util.List;

import org.realteam.base.dao.BaseDao;
import org.realteam.example.model.TestBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * This example is to illustrate how to design service layer,the part of
 * transactions In particular.
 * 
 * @author Harry
 * @version 1.0 Created On：2011-12-23 下午7:18:03
 * 
 */

@Service
@Transactional
public class ExampleMangerImpl implements ExampleManager {

	@Autowired
	@Qualifier("baseTransactionTemplate")
	private TransactionTemplate baseTransactionTemplate;

	@Autowired
	@Qualifier("txManager")
	private PlatformTransactionManager transactionManager;

	private TransactionTemplate transactionTemplate;

	@Autowired
	private BaseDao dao;

	@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
	public void findObject(String hql) throws Exception {
		dao.find(hql);
	}

	@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
	public Object load(Serializable oid, Class<?> clazz) throws Exception {
		TestBean t = new TestBean();
		t.setName("Steven");
		updateObject(t);

		return dao.load(oid, clazz);
	}

	public Object load0(Serializable oid, Class<?> clazz) throws Exception {
		TestBean t = new TestBean();
		t.setName("Lily");
		updateObject(t);
		
		return dao.load(oid, clazz);
	}

	@Transactional(readOnly = true)
	public void queryObject() throws Exception {
		// TODO
	}

	public void updateObject(Object o) throws Exception {
		dao.saveOrUpdate(o);
	}

	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public void updateObjectInNewTransaction(Object o) throws Exception {
		dao.saveOrUpdate(o);
	}

	@Transactional(propagation = Propagation.NOT_SUPPORTED)
	public <T> void batchUpdateObject(final List<T> l) throws Exception {
		transactionTemplate = new TransactionTemplate(transactionManager);
		transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
		transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
		transactionTemplate.setTimeout(30);

		for (final Object object : l) {
			transactionTemplate.execute(new TransactionCallbackWithoutResult() {
				protected void doInTransactionWithoutResult(TransactionStatus status) {
					try {
						updateObject(object);
					} catch (Exception e) {
						status.setRollbackOnly();
					}
				}
			});
		}

	}

	public <T> void batchUpdateOnlyOnce(final List<T> l) throws Exception {
		for (final Object object : l) {
			updateObject(object);
		}
	}

	@Transactional(propagation = Propagation.NOT_SUPPORTED)
	public void doBizWithNoTransaction() {
		TestBean bean = new TestBean();
		bean.setName("Frank");
		dao.saveOrUpdate(bean);
	}

	public void doBizUseTransactionTemplate() {
		baseTransactionTemplate.execute(new TransactionCallbackWithoutResult() {

			protected void doInTransactionWithoutResult(TransactionStatus status) {
				try {
					// do some logic
				} catch (Exception e) {
					status.setRollbackOnly();
				}
			}
		});

	}

}
